home *** CD-ROM | disk | FTP | other *** search
- Subject: v18i030: Mail user's shell version 6.4, Part08/19
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Dan Heller <island!argv@sun.com>
- Posting-number: Volume 18, Issue 30
- Archive-name: mush6.4/part08
-
-
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 8 (of 19)."
- # Contents: misc.c setopts.c
- # Wrapped by rsalz@papaya.bbn.com on Mon Mar 13 19:25:14 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'misc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'misc.c'\"
- else
- echo shar: Extracting \"'misc.c'\" \(18158 characters\)
- sed "s/^X//" >'misc.c' <<'END_OF_FILE'
- X/* @(#)misc.c (c) copyright 10/18/86 (Dan Heller) */
- X
- X#include "mush.h"
- X
- X/* check to see if a string describes a message that is within the range of
- X * all messages; if invalid, return 0 and print error. else return msg number
- X */
- Xchk_msg(s)
- Xregister char *s;
- X{
- X register int n;
- X
- X if ((n = atoi(s)) > 0 && n <= msg_cnt)
- X return n;
- X else if (*s == '^' && msg_cnt)
- X return 1;
- X else if (*s == '$' && msg_cnt)
- X return msg_cnt;
- X else if (*s == '.' && msg_cnt)
- X return current_msg+1;
- X print("Invalid message number: %s\n", s);
- X return 0;
- X}
- X
- X/*
- X * loop thru all msgs starting with current_msg and find next undeleted and
- X * unsaved message. If the variable "wrap" is set, wrap to the beginning of
- X * the message list if we hit the end. otherwise, stop at the end of the list.
- X */
- Xnext_msg()
- X{
- X register int n = current_msg;
- X register int wrap = !!do_set(set_options, "wrap");
- X
- X if (!msg_cnt)
- X return current_msg = 0;
- X for (n++; n != current_msg; n++)
- X if (n == msg_cnt) /* hit the end, start back at the beginning */
- X if (!wrap)
- X return current_msg;
- X else
- X n = -1; /* increments to 0 in loop */
- X else if (isoff(msg[n].m_flags, DELETE) &&
- X isoff(msg[n].m_flags, SAVED))
- X return current_msg = n;
- X return current_msg = 0;
- X}
- X
- X/* since print_help just prints help, always return help() */
- Xprint_help(argc, argv)
- Xregister char **argv;
- X{
- X#ifdef SUNTOOL
- X if (istool)
- X return help(tool->tl_windowfd, "general", tool_help);
- X#endif /* SUNTOOL */
- X if (!argc || !*++argv)
- X return help(0, "general", cmd_help);
- X return help(0, *argv, cmd_help);
- X}
- X
- X/* since this function does not affect messages, return -1 */
- Xhelp(fd, str, file)
- X#ifdef SUNTOOL
- Xcaddr_t *str;
- X#else
- Xchar *str;
- X#endif /* SUNTOOL */
- Xchar *file;
- X{
- X#ifdef SUNTOOL
- X if (istool > 1) {
- X int oldmask;
- X if (!fd)
- X fd = print_sw->ts_windowfd;
- X oldmask = sigblock(1 << ((SIGALRM) - 1));
- X lock_cursors();
- X if (display_help(fd, str, file, fonts[LARGE]) && file)
- X error("can't read %s", file);
- X unlock_cursors();
- X (void) sigsetmask(oldmask);
- X } else
- X#endif /* SUNTOOL */
- X if (find_help(str, file) && file)
- X error("can't read %s", file);
- X return 0; /* doesn't affect any messages */
- X}
- X
- X#ifdef SUNTOOL
- Xvoid
- Xunlock_cursors()
- X{
- X if (istool < 2)
- X return;
- X win_setcursor(print_sw->ts_windowfd, &main_cursor);
- X win_setcursor(panel_sw->ts_windowfd, &main_cursor);
- X if (getting_opts)
- X win_setcursor(msg_sw->ts_windowfd, &checkmark);
- X else if (ison(glob_flags, IS_GETTING))
- X win_setcursor(msg_sw->ts_windowfd, &write_cursor);
- X else
- X win_setcursor(msg_sw->ts_windowfd, &read_cursor);
- X win_setcursor(hdr_panel_sw->ts_windowfd, &main_cursor);
- X win_setcursor(hdr_sw->ts_windowfd, &l_cursor);
- X}
- X
- Xvoid
- Xlock_cursors()
- X{
- X if (istool < 2)
- X return;
- X win_setcursor(hdr_sw->ts_windowfd, &coffee);
- X win_setcursor(print_sw->ts_windowfd, &coffee);
- X win_setcursor(panel_sw->ts_windowfd, &coffee);
- X win_setcursor(msg_sw->ts_windowfd, &coffee);
- X win_setcursor(hdr_panel_sw->ts_windowfd, &coffee);
- X}
- X
- X#include <suntool/fullscreen.h>
- X/* return the event-id that confirmed */
- Xconfirm(fd)
- X{
- X struct fullscreen *fs;
- X
- X struct inputmask im;
- X struct inputevent event;
- X
- X fs = fullscreen_init(fd);
- X input_imnull(&im);
- X im.im_flags |= IM_ASCII;
- X win_setinputcodebit(&im, MS_LEFT);
- X win_setinputcodebit(&im, MS_MIDDLE);
- X win_setinputcodebit(&im, MS_RIGHT);
- X win_setinputmask(fd, &im, &im, WIN_NULLLINK);
- X win_setcursor(fd, &l_cursor);
- X if (input_readevent(fd, &event) == -1)
- X error("confirm failed");
- X fullscreen_destroy(fs);
- X return ID;
- X}
- X#endif /* SUNTOOL */
- X
- X/* return -1 on error or number of arguments in argv that were parsed */
- Xget_msg_list(argv, list)
- Xregister char **argv;
- Xchar list[];
- X{
- X register char *p2, *p, *end, ch;
- X char buf[BUFSIZ];
- X register int n;
- X
- X if (!msg_cnt) {
- X print("No messages.\n");
- X return -1;
- X }
- X if (!argv || !*argv) {
- X if (isoff(glob_flags, IS_PIPE))
- X set_msg_bit(list, current_msg);
- X return 0;
- X }
- X /* first, stuff argv's args into a single char array buffer */
- X (void) argv_to_string(buf, argv);
- X p = buf;
- X
- X Debug("get_msg_list: parsing: (%s): ", p);
- X /* find the end of the message list */
- X skipmsglist(0);
- X end = p;
- X while (*end && end != buf && !isspace(*end))
- X --end;
- X ch = *end, *end = '\0'; /* temporarily plug with nul */
- X p = buf; /* reset to the beginning */
- X /*
- X * if do_range returns NULL, an invalid message was specified
- X */
- X if (!(p2 = do_range(p, list))) {
- X *end = ch; /* just in case */
- X return -1;
- X }
- X /*
- X * if p2 == p (and p isn't $ or ^ or .), then no message list was
- X * specified. set the current message in such cases if we're not piping
- X */
- X if (p2 == p) {
- X if (*p == '$')
- X set_msg_bit(list, msg_cnt-1);
- X else if (*p == '^')
- X set_msg_bit(list, 0);
- X else if (*p == '.' || isoff(glob_flags, IS_PIPE))
- X set_msg_bit(list, current_msg);
- X }
- X for (n = 0; p2 > p && *argv; n++)
- X p2 -= (strlen(*argv++)+1);
- X Debug("parsed %d args\n", n);
- X *end = ch;
- X return n;
- X}
- X
- X/*
- X * execute a command from a string. f'rinstance: "pick -f foobar"
- X * The string is made into an argv and then run. Errors are printed
- X * if the command failed to make.
- X * NOTES:
- X * NEVER pass straight text: e.g. "pick -f foobar", ALWAYS strcpy(buf, "...")
- X * no history is expanded (ignore_bang).
- X */
- Xcmd_line(buf, list)
- Xchar buf[], list[];
- X{
- X register char **argv;
- X int argc, ret_val = -1;
- X u_long save_do_pipe = ison(glob_flags, DO_PIPE);
- X u_long save_is_pipe = ison(glob_flags, IS_PIPE);
- X char dummy_list[MAXMSGS_BITS];
- X
- X turnoff(glob_flags, DO_PIPE);
- X turnoff(glob_flags, IS_PIPE);
- X if (argv = make_command(buf, TRPL_NULL, &argc))
- X ret_val = do_command(argc, argv, list? list : dummy_list);
- X if (save_do_pipe)
- X turnon(glob_flags, DO_PIPE);
- X else
- X turnoff(glob_flags, DO_PIPE);
- X if (save_is_pipe)
- X turnon(glob_flags, IS_PIPE);
- X else
- X turnoff(glob_flags, IS_PIPE);
- X return ret_val;
- X}
- X
- Xglob_test(s)
- Xchar *s;
- X{
- X print("%s: glob_flags =", s);
- X if (ison(glob_flags, DO_UPDATE))
- X print_more(" DO_UPDATE");
- X if (ison(glob_flags, REV_VIDEO))
- X print_more(" REV_VIDEO");
- X if (ison(glob_flags, CONT_PRNT))
- X print_more(" CONT_PRNT");
- X if (ison(glob_flags, DO_SHELL))
- X print_more(" DO_SHELL");
- X if (ison(glob_flags, DO_PIPE))
- X print_more(" DO_PIPE");
- X if (ison(glob_flags, IS_PIPE))
- X print_more(" IS_PIPE");
- X if (ison(glob_flags, IGN_SIGS))
- X print_more(" IGN_SIGS");
- X if (ison(glob_flags, IGN_BANG))
- X print_more(" IGN_BANG");
- X if (ison(glob_flags, ECHO_FLAG))
- X print_more(" ECHO_FLAG");
- X if (ison(glob_flags, IS_GETTING))
- X print_more(" IS_GETTING");
- X if (ison(glob_flags, PRE_CURSES))
- X print_more(" PRE_CURSES");
- X if (ison(glob_flags, READ_ONLY))
- X print_more(" READ_ONLY");
- X if (ison(glob_flags, REDIRECT))
- X print_more(" REDIRECT");
- X if (ison(glob_flags, WAS_INTR))
- X print_more(" WAS_INTR");
- X if (ison(glob_flags, WARNING))
- X print_more(" WARNING");
- X if (ison(glob_flags, NEW_MAIL))
- X print_more(" NEW_MAIL");
- X if (ison(glob_flags, CNTD_CMD))
- X print_more(" CNTD_CMD");
- X if (ison(glob_flags, IS_SENDING))
- X print_more(" IS_SENDING");
- X if (ison(glob_flags, MIL_TIME))
- X print_more(" MIL_TIME");
- X if (ison(glob_flags, DATE_RECV))
- X print_more(" DATE_RECV");
- X if (ison(glob_flags, IN_MACRO))
- X print_more(" IN_MACRO");
- X if (ison(glob_flags, LINE_MACRO))
- X print_more(" LINE_MACRO");
- X if (ison(glob_flags, QUOTE_MACRO))
- X print_more(" QUOTE_MACRO");
- X print_more("\n");
- X}
- X
- X/*
- X * change the status flags for messages.
- X * flags * P preserves all messages.
- X * flags 4-7 -S remove the "saved" status on msgs 4-7
- X * flags +r add the replied-to bit on the current message.
- X */
- Xmsg_flags(c, v, list)
- Xregister char **v, *list;
- X{
- X register int i, modify = 0;
- X register u_long newflag = 0;
- X char sent[32], recv[32];
- X
- X if (c && *++v && !strcmp(*v, "-?"))
- X return help(0, "msg_flags", cmd_help);
- X if (c && (c = get_msg_list(v, list)) == -1)
- X return -1;
- X if (v && *(v += (c-1))) {
- X turnon(glob_flags, DO_UPDATE);
- X while (*++v)
- X for (c = 0; v[0][c]; c++)
- X switch (lower(v[0][c])) {
- X case 'n' : turnon(newflag, UNREAD), turnoff(newflag, OLD);
- X when 'd' : turnon(newflag, DELETE);
- X when 'p' : turnon(newflag, PRESERVE);
- X when 's' : turnon(newflag, SAVED);
- X when 'u' : turnon(newflag, UNREAD); /* fall thru! */
- X case 'o' : turnon(newflag, OLD);
- X when 'r' :
- X if (v[0][c] == 'R')
- X turnoff(newflag, UNREAD), turnon(newflag, OLD);
- X else
- X turnon(newflag, REPLIED);
- X when '+' : modify = 1;
- X when '-' : modify = 2;
- X otherwise: return help(0, "msg_flags", cmd_help);
- X }
- X }
- X
- X for (i = 0; i < msg_cnt; i++) {
- X if (!msg_bit(list, i))
- X continue;
- X else if (!newflag) {
- X wprint("msg %d: offset: %d, lines: %d, bytes: %d, flags:", i+1,
- X msg[i].m_offset, msg[i].m_lines, msg[i].m_size);
- X if (ison(msg[i].m_flags, UNREAD))
- X wprint(" UNREAD");
- X if (ison(msg[i].m_flags, OLD))
- X wprint(" OLD");
- X if (ison(msg[i].m_flags, DELETE))
- X wprint(" DELETE");
- X if (ison(msg[i].m_flags, PRESERVE))
- X wprint(" PRESERVE");
- X if (ison(msg[i].m_flags, REPLIED))
- X wprint(" REPLIED");
- X if (ison(msg[i].m_flags, SAVED))
- X wprint(" SAVED");
- X if (ison(msg[i].m_flags, UPDATE_STATUS))
- X wprint(" UPDATE_STATUS");
- X strcpy(sent, date_to_ctime(msg[i].m_date_sent));
- X strcpy(recv, date_to_ctime(msg[i].m_date_recv));
- X wprint("\n\tsent: %s\trecv: %s", sent, recv);
- X } else switch (modify) {
- X case 0: msg[i].m_flags = newflag;
- X when 1: msg[i].m_flags |= newflag;
- X when 2: msg[i].m_flags &= ~newflag;
- X }
- X }
- X return 0;
- X}
- X
- X/*
- X * Internal pager. Start the internal pager by passing the name of
- X * the pager in buf and passing TRUE as start_pager. If the internal
- X * pager is desired, pass NULL as buf. Continue paging by passing
- X * FALSE as start_pager and the buf is the stuff to pass thru to the
- X * pager. End paging by passing NULL as buf and FALSE as start_pager.
- X * If the pager can't be used, or is null, we're paging ourselves.
- X * Windows does nothing but echo buf to the msg window (this will change).
- X * The "buf" passed to the pager should be a line at a time so as to
- X * count \n's. If there is more than one newline, the first one is nulled
- X * and the next line done by calling do_pager recursively. WARNING: because
- X * "buf" is changed, it is *illegal* for anyone calling this routine to pass
- X * _constant_ strings --they should be strcpy'ed or sprintf'ed into a temp
- X * buff before passing to this routine! Otherwise, ANSI-C compilers will
- X * core dump. This is because constant strings are read-only.
- X * Return EOF if pager died, user exited pager, or if user types 'q'
- X * at the --more-- prompt for the internal pager.
- X */
- Xdo_pager(buf, start_pager)
- Xregister char *buf;
- X{
- X static FILE *pp;
- X static int cnt, len;
- X static u_long save_echo_flag;
- X
- X#ifdef SUNTOOL
- X if (istool) {
- X if (buf && !start_pager)
- X Addstr(buf);
- X return 0;
- X }
- X#endif /* SUNTOOL */
- X if (start_pager) {
- X turnon(glob_flags, IGN_SIGS);
- X if (!buf) {
- X /* internal pager */
- X save_echo_flag = ison(glob_flags, ECHO_FLAG);
- X pp = stdout;
- X if (save_echo_flag) {
- X turnoff(glob_flags, ECHO_FLAG);
- X echo_off();
- X }
- X } else {
- X echo_on();
- X if (!(pp = popen(buf, "w")))
- X error(buf);
- X }
- X cnt = len = 0;
- X } else if (!buf) {
- X if (pp && pp != stdout)
- X pclose(pp);
- X pp = NULL_FILE;
- X if (save_echo_flag) {
- X echo_on();
- X turnon(glob_flags, ECHO_FLAG);
- X } else
- X echo_off();
- X turnoff(glob_flags, IGN_SIGS);
- X } else if (pp != stdout)
- X return fputs(buf, pp); /* returns EOF if user exited pager */
- X else {
- X register char c = 0, *cr = index(buf, '\n');
- X len += strlen(buf);
- X if (cr) {
- X int maxlen =
- X#ifdef CURSES
- X iscurses ? COLS :
- X#endif /* CURSES */
- X 80;
- X if (len > maxlen)
- X cnt += len / maxlen;
- X len = 0;
- X }
- X if (cr && (c = *++cr) != '\0')
- X *cr = 0; /* send one line to stdout and prompt for more */
- X (void) fputs(buf, pp);
- X if (cr && (++cnt / (crt-1))) {
- X int n = c_more(NULL);
- X if (n == '\n' || n == '\r')
- X cnt--; /* go line by line */
- X else if (n == CTRL(D) || lower(n) == 'd' || n < 0) {
- X clearerr(stdin);
- X cnt = ((crt-1)/2);
- X } else if (lower(n) == 'q')
- X /* could check if "c" is set, but... see warning above */
- X return EOF;
- X else
- X cnt = 1;
- X }
- X if (c) {
- X *cr = c;
- X return do_pager(cr, FALSE);
- X }
- X }
- X return 0;
- X}
- X
- X/* curses based "more" like option */
- Xc_more(p)
- Xregister char *p;
- X{
- X register int c;
- X
- X if (!p)
- X p = "--more--";
- X print_more(p);
- X
- X while ((c = getchar()) >= 0 && c != CTRL(D) && !isspace(c) &&
- X c != '\n' && c != '\r' && lower(c) != 'q' && lower(c) != 'd')
- X bell();
- X if (ison(glob_flags, ECHO_FLAG) && c != '\n' && c != '\r')
- X while (getchar() != '\n');
- X printf("\r%*c\r", strlen(p), ' '), fflush(stdout); /* remove the prompt */
- X return c;
- X}
- X
- X/*
- X * Your "signature" is of the type:
- X * file_or_path
- X * $variable
- X * \ literal string preceded by a backslash.
- X * The variable will be expanded into its string value.
- X * To sign the letter, the list of addresses is passed to this routine
- X * (separated by whitespace and/or commas). No comment fields!
- X *
- X * If "autosign2" is set, then it must be of the form:
- X * autosign2 = "*user user !host !some!path @dom.ain: ~/.sign2"
- X *
- X * The colon terminates the user/host lists from the "signature" to the right.
- X *
- X * Whitespace or commas separate tokens. If everyone on the list exists in
- X * the autosign2 list, the alternate signature is used. In case of syntax
- X * error, the alternate signature is used without checks (e.g. if the colon
- X * is missing). The alternate signature == null is the same as not signing
- X * the letter. An empty list forces signature2.
- X *
- X * If autosign2 is not set at all, then autosign is checked and used.
- X * autosign = <signature>
- X */
- Xsign_letter(list, flags, fp)
- Xregister char *list; /* list of addresses -- no comment fields */
- Xu_long flags;
- XFILE *fp;
- X{
- X char buf[BUFSIZ], *signature;
- X register char *p = NULL, *p2;
- X FILE *pp2;
- X int lines = 0;
- X
- X while (isspace(*list))
- X list++;
- X if (ison(flags, SIGN)) {
- X if (!(p = do_set(set_options, "autosign2")))
- X buf[0] = 0;
- X else {
- X if (!(signature = index(p, ':')))
- X (void) strcpy(buf, p); /* No colon; use entire string as sig */
- X else {
- X int ret_val = 0;
- X *signature = 0;
- X /* p now points to a list of addresses and p2 points to the
- X * signature format to use. Check that each address in the list
- X * provided (parameter) matches the "addrs" in autosign2.
- X */
- X skipspaces(0);
- X if (!*p)
- X /* autosign2 = " : <signature>" send to all recipients */
- X ret_val = 1;
- X else if (p = alias_to_address(p)) {
- X rm_cmts_in_addr(p);
- X ret_val = compare_addrs(list, p, NULL);
- X }
- X *signature++ = ':'; /* must reset first! */
- X buf[0] = 0;
- X if (ret_val) {
- X while (isspace(*signature))
- X signature++;
- X /* Null signatures don't sign anything. */
- X if (!*strcpy(buf, signature))
- X return;
- X }
- X }
- X }
- X if (!buf[0]) {
- X if (!(p = do_set(set_options, "autosign")) || !*p) {
- X char *home;
- X if (!(home = do_set(set_options, "home")) || !*home)
- X home = ALTERNATE_HOME;
- X (void) sprintf(buf, "%s/%s", home, SIGNATURE);
- X } else
- X (void) strcpy(buf, p);
- X wprint("Signing letter... ");
- X } else
- X wprint("Using alternate signature... ");
- X /* precede _file_ signatures ONLY with "\n-- \n" */
- X if (buf[0] != '\\' && buf[0] != '$')
- X fputs("\n-- \n", fp);
- X else
- X fputc('\n', fp);
- X fflush(fp);
- X (void) fseek(fp, 0L, 2); /* guarantee position at end of file */
- X if (*buf == '$')
- X if (!(p = do_set(set_options, buf)))
- X wprint("(%s isn't set -- letter not signed)\n", buf);
- X else {
- X putstring(p+1, fp);
- X wprint("\n");
- X }
- X else if (*buf == '\\') {
- X putstring(buf, fp);
- X wprint("\n");
- X } else
- X file_to_fp(buf, fp, "r");
- X }
- X
- X fflush(stdout); /* for sys-v and older xenix */
- X
- X /* if fortune is set, check to see if fortunates is set. If so,
- X * check to see if all the recipient are on the fortunates list.
- X */
- X if (ison(flags, DO_FORTUNE)) {
- X if (p = do_set(set_options, "fortunates")) {
- X int ret_val;
- X if (!(p = alias_to_address(p)))
- X return; /* no reason to hang around */
- X rm_cmts_in_addr(p);
- X if (!compare_addrs(list, p, buf)) {
- X wprint("\"fortunates\" does not contain \"%s\".\n", buf);
- X wprint("No fortune added.\n");
- X return;
- X }
- X }
- X wprint("You may be fortunate... ");
- X if ((p = do_set(set_options, "fortune")) && *p == '/')
- X (void) strcpy(buf, p);
- X else
- X (void) sprintf(buf, "%s %s", FORTUNE, (p && *p == '-')? p: "-s");
- X if (!(pp2 = popen(buf, "r")))
- X error(buf);
- X else {
- X turnon(glob_flags, IGN_SIGS);
- X (void) fseek(fp, 0L, 2); /* go to end of file */
- X while (fgets(buf, sizeof(buf), pp2))
- X fputs(buf, fp), lines++;
- X (void) pclose(pp2);
- X turnoff(glob_flags, IGN_SIGS);
- X fflush(fp);
- X wprint("added %d line%s\n", lines, lines == 1? "" : "s");
- X }
- X }
- X fflush(stdout); /* for sys-v and older xenix */
- X}
- X
- X
- X/* return -1 since function doesn't affect messages */
- Xcheck_flags(flags)
- Xu_long flags;
- X{
- X print_more(" ");
- X if (ison(flags, VERBOSE))
- X print_more("VERBOSE ");
- X if (ison(flags, INCLUDE))
- X print_more("INCLUDE ");
- X if (ison(flags, INCLUDE_H))
- X print_more("INCLUDE_H ");
- X if (ison(flags, EDIT))
- X print_more("EDIT ");
- X if (ison(flags, SIGN))
- X print_more("SIGN ");
- X if (ison(flags, DO_FORTUNE))
- X print_more("DO_FORTUNE ");
- X if (ison(flags, NO_HEADER))
- X print_more("NO_HEADER ");
- X if (ison(flags, DELETE))
- X print_more("DELETE ");
- X if (ison(flags, OLD))
- X print_more("OLD ");
- X if (ison(flags, UNREAD))
- X print_more("UNREAD ");
- X if (ison(flags, UPDATE_STATUS))
- X print_more("UPDATE_STATUS ");
- X if (ison(flags, NO_PAGE))
- X print_more("NO_PAGE ");
- X if (ison(flags, INDENT))
- X print_more("INDENT ");
- X if (ison(flags, NO_IGNORE))
- X print_more("NO_IGNORE ");
- X if (ison(flags, PRESERVE))
- X print_more("PRESERVE ");
- X print_more("\n");
- X return -1;
- X}
- END_OF_FILE
- if test 18158 -ne `wc -c <'misc.c'`; then
- echo shar: \"'misc.c'\" unpacked with wrong size!
- fi
- # end of 'misc.c'
- fi
- if test -f 'setopts.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'setopts.c'\"
- else
- echo shar: Extracting \"'setopts.c'\" \(18443 characters\)
- sed "s/^X//" >'setopts.c' <<'END_OF_FILE'
- X/* setopts.c (c) copyright 1986 (Dan Heller) */
- X
- X#include "mush.h"
- X#include "bindings.h"
- X
- X/* add an option indicated by "set option[=value]" or by "alias name alias"
- X * function is recursive, so multilists get appended accordingly
- X */
- Xadd_option(list, argv)
- Xregister struct options **list;
- Xregister char **argv;
- X{
- X register struct options *tmp;
- X struct options *calloc();
- X register char *option, *value = NULL;
- X
- X if (!(option = *argv))
- X return 1;
- X /* check for one of three forms:
- X * option=value option = value option= value
- X * value can be in quotes to preserve whitespace
- X */
- X if (*++argv && !strcmp(*argv, "=")) {
- X if (value = *++argv) /* example: "set foo = " */
- X ++argv;
- X } else if (value = index(option, '=')) {
- X /* option=value strip into option="option" value="value"; (quotes?) */
- X register char c, *p2;
- X *value = 0; /* option is now a null terminated `option' */
- X if ((c = *++value) == '"' || c == '\'') {
- X *value++ = 0;
- X if (!(p2 = index(value, c))) {
- X print("No matching %c for %s.\n", c, option);
- X return 0;
- X } else
- X *p2 = 0;
- X } else if (!c) { /* example: "set crt=" */
- X if (!*argv) {
- X print("No value for %s.\n", option);
- X return 0;
- X }
- X value = *argv++;
- X }
- X }
- X
- X /* check for internal vars that can't be set this way */
- X if (check_internal(option)) {
- X print("You can't change %s with \"set\".\n", option);
- X return 0;
- X }
- X
- X /* check to see if option is already set by attempting to unset it */
- X (void) un_set(list, option);
- X
- X /* now make a new option struct and set fields */
- X if (!(tmp = calloc((unsigned)1, sizeof(struct options)))) {
- X error("calloc");
- X return -1;
- X }
- X tmp->option = savestr(option);
- X tmp->value = savestr(value); /* strdup handles the NULL case */
- X
- X tmp->next = *list;
- X *list = tmp;
- X
- X /* check for options which must have values or are used frequently */
- X if (*list == set_options) {
- X#if defined(CURSES) || defined(SUNTOOL)
- X if (!strcmp(tmp->option, "no_reverse"))
- X turnoff(glob_flags, REV_VIDEO);
- X else
- X#endif /* CURSES || SUNTOOL */
- X if (!strcmp(tmp->option, "prompt"))
- X prompt = (tmp->value)? tmp->value : DEF_PROMPT;
- X else if (!strcmp(tmp->option, "warning"))
- X turnon(glob_flags, WARNING);
- X else if (!strcmp(tmp->option, "mil_time"))
- X turnon(glob_flags, MIL_TIME);
- X#ifndef MSG_SEPARATOR
- X else if (!strcmp(tmp->option, "date_received"))
- X turnon(glob_flags, DATE_RECV);
- X#endif /* MSG_SEPARATOR */
- X else if (!strcmp(tmp->option, "escape"))
- X escape = (tmp->value)? tmp->value : DEF_ESCAPE;
- X else if (!strcmp(tmp->option, "hdr_format"))
- X hdr_format = (tmp->value)? tmp->value : DEF_HDR_FMT;
- X else if (!strcmp(tmp->option, "crt")) {
- X if (!istool)
- X crt = (tmp->value)? max(atoi(tmp->value), 2): 18;
- X } else if (!strcmp(tmp->option, "screen")) {
- X screen = (tmp->value)? max(atoi(tmp->value), 1): 18;
- X#ifdef CURSES
- X if (iscurses && screen > LINES-2)
- X screen = LINES-2;
- X#endif /* CURSES */
- X } else if (!strcmp(tmp->option, "wrapcolumn")) {
- X char wval[16];
- X wrapcolumn =
- X (tmp->value && *(tmp->value))? max(atoi(tmp->value), 0): 78;
- X#ifdef CURSES
- X /* Use COLS-2 because of silly terminals like vt100 */
- X if (iscurses && wrapcolumn > COLS - 2)
- X wrapcolumn = COLS - 2;
- X#endif /* CURSES */
- X xfree(tmp->value);
- X tmp->value = savestr(sprintf(wval, "%d", wrapcolumn));
- X } else if (!strcmp(tmp->option, "history"))
- X init_history((value && *value)? atoi(value) : 1);
- X else if (!strcmp(tmp->option, "known_hosts")) {
- X register char *p;
- X int n;
- X /* in case user separated with commas */
- X for (p = index(tmp->value, ','); p; p = index(p+1, ','))
- X *p = ' ';
- X free_vec(known_hosts);
- X known_hosts = mk_argv(tmp->value, &n, FALSE);
- X } else if (!strcmp(tmp->option, "hostname")) {
- X register char *p;
- X int n;
- X /* in case user separated with commas */
- X for (p = index(tmp->value, ','); p; p = index(p+1, ','))
- X *p = ' ';
- X free_vec(ourname);
- X ourname = mk_argv(tmp->value, &n, FALSE);
- X }
- X }
- X
- X if (*argv)
- X return add_option(list, argv);
- X return 1;
- X}
- X
- X/*
- X * If str is NULL, just print options and their values. Note that numerical
- X * values are not converted to int upon return. If str is not NULL
- X * return the string that matched, else return NULL;
- X */
- Xchar *
- Xdo_set(list, str)
- Xregister struct options *list;
- Xregister char *str;
- X{
- X register struct options *opts;
- X#ifdef SUNTOOL
- X int x,y;
- X
- X if (istool && !str)
- X y = 10 + 2 * l_height(LARGE);
- X#endif /* SUNTOOL */
- X
- X if (!str && !istool)
- X (void) do_pager(NULL, TRUE); /* page using internal pager */
- X
- X for (opts = list; opts; opts = opts->next)
- X if (!str) {
- X#ifdef SUNTOOL
- X if (istool)
- X pw_text(msg_win, 5, y, PIX_SRC, fonts[DEFAULT], opts->option);
- X else
- X#endif /* SUNTOOL */
- X (void) do_pager(opts->option, FALSE);
- X if (opts->value)
- X#ifdef SUNTOOL
- X if (istool) {
- X x = 30*l_width(DEFAULT);
- X pw_text(msg_win, x,y, PIX_SRC, fonts[DEFAULT], opts->value);
- X pw_text(msg_win, x+1, y, PIX_SRC|PIX_DST,
- X fonts[DEFAULT], opts->value);
- X x += strlen(opts->value)*l_width(DEFAULT);
- X } else
- X#endif /* SUNTOOL */
- X {
- X (void) do_pager(" \t", FALSE);
- X (void) do_pager(opts->value, FALSE);
- X }
- X#ifdef SUNTOOL
- X if (istool)
- X Clrtoeol(msg_win, x, y, DEFAULT), y += l_height(DEFAULT);
- X else
- X#endif /* SUNTOOL */
- X if (do_pager("\n", FALSE) == EOF)
- X break;
- X } else {
- X if (strcmp(str, opts->option))
- X continue;
- X if (opts->value)
- X return opts->value;
- X else
- X return "";
- X }
- X
- X if (!str && !istool)
- X (void) do_pager(NULL, FALSE); /* terminate internal pager */
- X
- X /* if we still haven't matched, check for environment vars */
- X if (str && list == set_options) {
- X register int N, n;
- X for (N = 0; environ[N]; N++) {
- X char *p = index(environ[N], '=');
- X if (p)
- X *p = 0;
- X n = lcase_strncmp(str, environ[N], -1);
- X if (p)
- X *p = '=';
- X if (!n)
- X return p+1;
- X }
- X }
- X return NULL;
- X}
- X
- X/*
- X * unset the variable described by p in the list "list".
- X * if the variable isn't set, then return 0, else return 1.
- X */
- Xun_set(list, p)
- Xregister struct options **list;
- Xregister char *p;
- X{
- X register struct options *opts = *list, *tmp;
- X
- X if (!list || !*list || !p || !*p)
- X return 0;
- X if (*list == set_options) {
- X#if defined(CURSES) || defined(SUNTOOL)
- X if (!strcmp(p, "no_reverse"))
- X turnon(glob_flags, REV_VIDEO);
- X else
- X#endif /* CURSES || SUNTOOL */
- X if (!strcmp(p, "prompt"))
- X prompt = DEF_PROMPT;
- X else if (!strcmp(p, "warning"))
- X turnoff(glob_flags, WARNING);
- X else if (!strcmp(p, "mil_time"))
- X turnoff(glob_flags, MIL_TIME);
- X#ifndef MSG_SEPARATOR
- X else if (!strcmp(p, "date_received"))
- X turnoff(glob_flags, DATE_RECV);
- X#endif /* MSG_SEPARATOR */
- X else if (!strcmp(p, "escape"))
- X escape = DEF_ESCAPE;
- X else if (!strcmp(p, "hdr_format"))
- X hdr_format = DEF_HDR_FMT;
- X else if (!strcmp(p, "crt"))
- X crt = 18;
- X else if (!strcmp(p, "screen")) {
- X screen = 18;
- X#ifdef CURSES
- X if (iscurses && screen > LINES-2)
- X screen = LINES-2;
- X#endif /* CURSES */
- X } else if (!strcmp(p, "wrapcolumn"))
- X wrapcolumn = 0;
- X else if (!strcmp(p, "history"))
- X init_history(1);
- X else if (!strcmp(p, "known_hosts")) {
- X free_vec(known_hosts);
- X known_hosts = DUBL_NULL;
- X } else if (!strcmp(p, "hostname")) {
- X free_vec(ourname);
- X ourname = DUBL_NULL;
- X }
- X }
- X
- X if (!strcmp(p, opts->option)) {
- X *list = (*list)->next;
- X xfree (opts->option);
- X if (opts->value)
- X xfree(opts->value);
- X xfree((char *)opts);
- X return 1;
- X }
- X for ( ; opts->next; opts = opts->next)
- X if (!strcmp(p, opts->next->option)) {
- X tmp = opts->next;
- X opts->next = opts->next->next;
- X xfree (tmp->option);
- X if (tmp->value)
- X xfree(tmp->value);
- X xfree ((char *)tmp);
- X return 1;
- X }
- X return 0;
- X}
- X
- X/* The functions below return 0 since they don't affect
- X * messages.
- X */
- Xset(n, argv, list)
- Xregister int n;
- Xregister char **argv;
- Xchar *list;
- X{
- X char firstchar = **argv;
- X register char *cmd = *argv;
- X register struct options **optlist;
- X char buf[BUFSIZ];
- X
- X if (*cmd == 'u')
- X cmd += 2;
- X if (*++argv && !strcmp(*argv, "-?"))
- X return help(0, (*cmd == 'i')? "ignore": "set", cmd_help);
- X
- X if (*argv && **argv == '?') {
- X int incurses;
- X if (!strcmp(*argv, "?all")) {
- X if (incurses = iscurses) /* assign and compare to TRUE */
- X clr_bot_line(), iscurses = FALSE;
- X (void) do_pager(NULL, TRUE); /* start internal pager */
- X for (n = 0; variable_stuff(n, NULL, buf); n++)
- X if (do_pager(strcat(buf, "\n"), FALSE) == EOF)
- X break;
- X (void) do_pager(NULL, FALSE); /* terminate pager */
- X iscurses = incurses;
- X } else {
- X /* May return null if variable not set. */
- X (void) variable_stuff(0, (*argv)+1, buf);
- X print("%s\n", buf);
- X }
- X return 0;
- X }
- X
- X if (firstchar == 'u') {
- X if (!*argv) {
- X print("%s what?\n", cmd);
- X return -1;
- X } else {
- X optlist = (*cmd == 'i')? &ignore_hdr : &set_options;
- X do if (!strcmp(*argv, "*"))
- X while (*optlist)
- X (void) un_set(optlist, (*optlist)->option);
- X else if (!un_set(optlist, *argv))
- X print("un%s: %s not set\n",
- X (*cmd == 'i')? "ignore" : "set", *argv);
- X while (*++argv);
- X }
- X return 0;
- X }
- X
- X if (!*argv) {
- X (void) do_set((*cmd == 'i')? ignore_hdr: set_options, NULL);
- X return 0;
- X }
- X
- X /*
- X * Check for input redirection. If so, set the variable to the ascii
- X * value of the current msg_list.
- X */
- X if (ison(glob_flags, IS_PIPE)) {
- X char *newargv[4];
- X
- X if (*cmd == 'i') {
- X print("You can't pipe to the \"%s\" command.\n", cmd);
- X return -1;
- X }
- X list_to_str(list, buf);
- X if (!buf[0])
- X return -1;
- X newargv[0] = argv[0];
- X newargv[1] = "=";
- X newargv[2] = buf;
- X newargv[3] = NULL;
- X (void) add_option(&set_options, newargv);
- X return 0;
- X }
- X
- X /*
- X * finally, just set the variable the user requested.
- X */
- X (void) add_option((*cmd == 'i')? &ignore_hdr: &set_options, argv);
- X return 0;
- X}
- X
- X/*
- X * The alts list is a list of hostnames or pathnames where the user
- X * has an account. If he doesn't specify "metoo", then when replying
- X * to mail, if his address is listed, it will be removed. The syntax
- X * is compatible with ucb Mail in that just hostnames can be used.
- X * However, there is an added feature that mush provides which another
- X * login name or path to another login can be specified by preceding the
- X * path or login with a !
- X * "argv" may be a file pointer to write the data into by use of save_opts()
- X */
- Xalts(argc, argv)
- Xregister char **argv;
- X{
- X char buf[BUFSIZ], *p;
- X
- X /* check here first because a 0 argc means to write it to a file */
- X if (argc <= 1) {
- X int n;
- X if (!alternates)
- X return;
- X if (argc == 0)
- X fprintf((FILE *)argv, "alts ");
- X for (n = 0; alternates[n]; n++) {
- X p = 0;
- X (void) reverse(strcpy(buf, alternates[n]));
- X if (isalpha(buf[0]) && (p = rindex(buf, '!')))
- X *p = 0;
- X if (argc == 0)
- X fprintf((FILE *)argv, "%s ", buf);
- X else
- X wprint("%s ", buf);
- X if (p)
- X *p = '!';
- X }
- X if (argc == 0)
- X fputc('\n', (FILE *)argv);
- X else
- X wprint("\n");
- X return 0;
- X }
- X
- X if (argc-- && *++argv && !strcmp(*argv, "-?"))
- X return help(0, "alts", cmd_help);
- X
- X free_vec(alternates);
- X if (alternates = (char **)calloc((unsigned)argc+1, sizeof(char *)))
- X while (argc-- > 0) {
- X if (argv[argc][0] != '!' && argv[argc][0] != '*') {
- X p = buf + Strcpy(buf, argv[argc]);
- X *p++ = '!', p += Strcpy(p, login);
- X alternates[argc] = savestr(reverse(buf));
- X } else
- X alternates[argc] = savestr(reverse(argv[argc]));
- X }
- X return 0;
- X}
- X
- Xsave_opts(cnt, argv)
- Xchar **argv;
- X{
- X char file[256], *tmp;
- X register FILE *fp;
- X
- X if (cnt && *++argv && !strcmp(*argv, "-?"))
- X return help(0, "source_help", cmd_help);
- X if (cnt && *argv)
- X (void) strcpy(file, *argv);
- X else if (tmp = getenv("MAILRC"))
- X (void) strcpy(file, tmp);
- X else {
- X char *home = do_set(set_options, "home");
- X if (!home || !*home)
- X home = ALTERNATE_HOME;
- X /* if .mushrc doesn't exist, check .mailrc. If neither, force .mushrc */
- X if (Access(sprintf(file, "%s/%s", home, MAILRC), F_OK) &&
- X Access(sprintf(file, "%s/%s", home, ALTERNATE_RC), F_OK))
- X (void) sprintf(file, "%s/%s", home, MAILRC);
- X }
- X
- X cnt = 1;
- X tmp = getpath(file, &cnt);
- X if (cnt) {
- X if (cnt == -1)
- X print("%s: %s\n", file, tmp);
- X else
- X print("%s is a directory.\n", tmp);
- X return -1;
- X }
- X /* See if the file exists and confirm overwrite */
- X if (!Access(tmp, F_OK)) {
- X int overwrite = TRUE;
- X char buf[4];
- X print("\"%s\" exists. Overwrite? ", tmp);
- X if (!istool) {
- X if (Getstr(buf, 3, 0) <= 0 || lower(*buf) != 'y')
- X overwrite = FALSE;
- X }
- X#ifdef SUNTOOL
- X else {
- X int c = confirm(panel_sw->ts_windowfd);
- X if (lower(c) != 'y' && c != MS_LEFT)
- X overwrite = FALSE;
- X }
- X#endif /* SUNTOOL */
- X if (!overwrite) {
- X print("\"%s\" unchanged.\n", tmp);
- X return -1;
- X }
- X }
- X if (!(fp = fopen(tmp, "w"))) {
- X error("Can't open %s", file);
- X return -1;
- X }
- X
- X save_list("basic variable settings", set_options, "set", '=', fp);
- X
- X save_list("mail headers for outgoing mail", own_hdrs, "my_hdr", 0, fp);
- X
- X save_list("aliases", aliases, "alias", 0, fp);
- X
- X alts(0, (char **)fp);
- X
- X save_list("headers to ignore", ignore_hdr, "ignore", ' ', fp);
- X
- X save_list("command abbreviations", functions, "cmd", ' ', fp);
- X
- X save_list("command macros for function keys", fkeys, "fkey", ' ', fp);
- X
- X#ifdef CURSES
- X save_cmd("curses mode key bindings", cmd_map, "bind", 1, fp);
- X#endif /* CURSES */
- X
- X save_cmd("line mode mappings", line_map, "map", 0, fp);
- X
- X save_cmd("composition mode mappings", bang_map, "map!", 0, fp);
- X
- X fclose(fp);
- X print("All variables and options saved in %s\n", tmp);
- X return -1;
- X}
- X
- Xsave_list(title, list, command, equals, fp)
- Xstruct options *list;
- Xregister char *command, *title, equals;
- Xregister FILE *fp;
- X{
- X register struct options *opts;
- X register char *p;
- X
- X if (!list)
- X return;
- X fprintf(fp, "#\n# %s\n#\n", title);
- X for (opts = list; opts; opts = opts->next) {
- X if (list == set_options && !strcmp(opts->option, "cwd"))
- X continue; /* don't print $cwd */
- X fprintf(fp, "%s %s", command, opts->option);
- X if (opts->value && *opts->value) {
- X register char *quote;
- X if (!equals)
- X quote = NO_STRING;
- X else if (p = any(opts->value, "\"'"))
- X if (*p == '\'') quote = "\"";
- X else quote = "'";
- X else
- X if (!any(opts->value, " \t;|"))
- X quote = NO_STRING;
- X else quote = "'";
- X fputc(equals? equals: ' ', fp);
- X fprintf(fp, "%s%s%s", quote, opts->value, quote);
- X }
- X fputc('\n', fp);
- X }
- X}
- X
- Xextern struct cmd_map map_func_names[];
- X
- Xsave_cmd(title, list, command, equals, fp)
- Xstruct cmd_map *list;
- Xregister char *command, *title;
- Xregister int equals;
- Xregister FILE *fp;
- X{
- X register struct cmd_map *opts;
- X register char *p;
- X char buf[MAX_MACRO_LEN * 2];
- X
- X if (!list)
- X return;
- X fprintf(fp, "#\n# %s\n#\n", title);
- X for (opts = list; opts; opts = opts->m_next) {
- X register char *quote;
- X if ((p = any(opts->m_str, "\"'")) && *p == '\'')
- X quote = "\"";
- X else
- X quote = "'";
- X fprintf(fp, "%s %s%s%s", command, quote,
- X ctrl_strcpy(buf, opts->m_str, TRUE), quote);
- X if (equals && map_func_names[opts->m_cmd].m_str)
- X fprintf(fp, " %s", map_func_names[opts->m_cmd].m_str);
- X if (opts->x_str && *opts->x_str) {
- X if ((p = any(opts->x_str, "\"'")) && *p == '\'')
- X quote = "\"";
- X else
- X quote = "'";
- X fprintf(fp, " %s%s%s", quote,
- X ctrl_strcpy(buf, opts->x_str, TRUE), quote);
- X }
- X fputc('\n', fp);
- X }
- X}
- X
- X/*
- X * do_alias handles aliases, header settings, functions, and fkeys.
- X * since they're all handled in the same manner, the same routine is
- X * used. argv[0] determines which to use.
- X * alias is given here as an example
- X *
- X * alias identify all aliases
- X * alias name identify alias
- X * alias name arg1 arg2 arg3... -> name="arg1 arg2 arg3"; call add_option
- X * unalias arg1 [arg2 arg3 ... ] unalias args
- X *
- X * same is true for dealing with your own headers.
- X * (also the expand command)
- X * always return -1 since it has no effect on messages
- X */
- Xdo_alias(argc, argv)
- Xregister char **argv;
- X{
- X register char *cmd = *argv, *p;
- X struct options **list;
- X char firstchar = *cmd, buf[BUFSIZ];
- X
- X if (argc == 0)
- X return 0 - in_pipe();
- X if (firstchar == 'u')
- X firstchar = cmd[2];
- X if (*++argv && !strcmp(*argv, "-?")) { /* doesn't apply for fkeys */
- X register char *help_str;
- X if (firstchar == 'a' || firstchar == 'e')
- X help_str = "alias";
- X else if (firstchar == 'c')
- X help_str = "cmd";
- X else if (firstchar == 'f')
- X help_str = "fkey";
- X else
- X help_str = "own_hdrs";
- X return help(0, help_str, cmd_help);
- X }
- X
- X if (firstchar == 'a')
- X list = &aliases;
- X else if (firstchar == 'c')
- X list = &functions;
- X else if (firstchar == 'f')
- X list = &fkeys;
- X else
- X list = &own_hdrs;
- X
- X if (*cmd == 'u') {
- X if (!*argv) {
- X print("%s what?\n", cmd);
- X return -1;
- X /* unset a list separated by spaces or ',' */
- X } else while (*argv) {
- X if (!strcmp(*argv, "*")) /* unset everything */
- X while (*list)
- X (void) un_set(list, (*list)->option);
- X else if (!un_set(list, *argv))
- X print("\"%s\" isn't set\n", *argv);
- X argv++;
- X }
- X return 0;
- X }
- X
- X if (!*argv && *cmd != 'e') {
- X /* just type out all the aliases or own_hdrs */
- X (void) do_set(*list, NULL);
- X return 0;
- X }
- X
- X if (*cmd == 'e') { /* command was "expand" (aliases only) */
- X if (!*argv) {
- X print("expand which alias?\n");
- X return -1;
- X } else
- X do {
- X print("%s: ", *argv);
- X if (p = alias_to_address(*argv))
- X print("%s\n", p);
- X } while (*++argv);
- X return 0;
- X }
- X
- X /* at this point, *argv now points to a variable name ...
- X * check for hdr -- if so, *argv better end with a ':' (check *p)
- X */
- X if (list == &own_hdrs && !(p = index(*argv, ':'))) {
- X print("header labels must end with a ':' (%s)\n", *argv);
- X return -1;
- X }
- X if (!argv[1] && !index(*argv, '='))
- X if (p = do_set(*list, *argv))
- X print("%s\n", p);
- X else
- X print("%s is not set\n", *argv);
- X else {
- X char *tmpargv[2];
- X (void) argv_to_string(buf, argv);
- X if ((p = any(buf, " \t=")) && *p != '=')
- X *p = '=';
- X /* if we're setting an alias, enforce the insertion of commas
- X * between each well-formed address.
- X */
- X if (list == &aliases)
- X fix_up_addr(p+1);
- X tmpargv[0] = buf;
- X tmpargv[1] = NULL;
- X (void) add_option(list, tmpargv);
- X }
- X return 0;
- X}
- END_OF_FILE
- if test 18443 -ne `wc -c <'setopts.c'`; then
- echo shar: \"'setopts.c'\" unpacked with wrong size!
- fi
- # end of 'setopts.c'
- fi
- echo shar: End of archive 8 \(of 19\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 19 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-